using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

#if WIIMOTE
using WiimoteLib;
#endif

namespace StupidSpaceThing.MenuSystem
{
	internal class TopMenu : Microsoft.Xna.Framework.Game
	{
		BaseGame game;
		GraphicsDeviceManager graphics;
		GraphicsDevice device;
		SpriteBatch spriteBatch;
		SpriteFont spriteFont;
		Camera camera;
		bool runGame = false;
		public static bool Paused = false;
		bool controllerConnected = false;
		TextGuide noController;
		TextGuide credits;
		public static float[] Vibration = new float[4];
		public static double TotalRealGameTimeMilliseconds = 0;

		Text logo;
		Text singleplayer;
		Text multiplayer;
		List<Text> curText = new List<Text>();
		List<Text> drawText = new List<Text>();
		List<Mine> mines = new List<Mine>();
        BackgroundObject box;
        private class BackgroundObject : Entity
        {
            public BackgroundObject(Model model, Vector3 position, float scale)
                : base(model, position, Quaternion.Identity, scale)
            {
                    random = new Random();
            }
            private Random random;
            private bool pitchControl = false;
            private bool rollControl = false;
            private bool yawControl = false;
            
            public void Update()
            {
                
                this.Rotate((pitchControl?1:-1)*0.01f, (yawControl?1:-1)*0.01f, (rollControl?1:-1)*0.01f);

                if (random.NextDouble() < 0.01f)
                {
                    pitchControl = random.Next(2) == 1;
                    rollControl = random.Next(2) == 1;
                    yawControl = random.Next(2) == 1;
                }
            }
        }

		bool leftThumbNeutral = true;
#if WIIMOTE
		bool wiimove = false;

		private static Wiimote mote;
		private const bool useWiiMote = false;
		public static WiimoteState WiiState = null;
		public static bool Nunchuk;
#endif
        public static TopMenu Menu;
		public static bool GameRunning = false;
		
		public TopMenu() {		
			graphics = new GraphicsDeviceManager(this);
			
#if XBOX
			graphics.PreferredBackBufferWidth = 1280; //defaults to 720p
			graphics.PreferredBackBufferHeight = 720;
#else
			float aspect = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height / (float)GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
			int width = 1024;
			graphics.PreferredBackBufferWidth = width;
			graphics.PreferredBackBufferHeight = (int)(width * aspect);
#if !DEBUG
            graphics.IsFullScreen = true;
#endif
#endif
			
			//graphics.IsFullScreen = true;
			Menu = this;
#if WIIMOTE
			if( useWiiMote ) {
				mote = new Wiimote();
				mote.WiimoteChanged += new WiimoteChangedEventHandler(Mote_WiimoteChanged);
				mote.WiimoteExtensionChanged += new WiimoteExtensionChangedEventHandler(Mote_WiimoteExtensionChanged);
				mote.Connect();
				Thread.Sleep(1000);
				mote.SetReportType(Wiimote.InputReport.IRAccel, true);
				if( Nunchuk ) {
					mote.SetReportType(Wiimote.InputReport.IRExtensionAccel, true);
				}
				mote.SetLEDs(false, true, true, false);

			}
 #endif
		}

		public void StopGame() {
			if( runGame ) {
				TotalRealGameTimeMilliseconds = 0;
				game.UnloadContent();
				game = null;
				runGame = false;
				GameRunning = false;
				mines = new List<Mine>();
				Bullets.Init(device);
			}
		}
#if WIIMOTE
		void Mote_WiimoteExtensionChanged(object sender, WiimoteExtensionChangedEventArgs args) {
			if( args.ExtensionType == ExtensionType.Nunchuk ) {				
				Nunchuk = args.Inserted;
			}
		}

		void Mote_WiimoteChanged(object sender, WiimoteChangedEventArgs args) {
			WiiState = args.WiimoteState;
		}
#endif

		protected override void Initialize() {
			device = graphics.GraphicsDevice;			
			spriteBatch = new SpriteBatch(device);
			TextureTools.Init(device);
			Entity.Init(device);
			camera = new Camera(device, new Vector3(0, 0, 130), 0, 0);
			camera.Rotate((float)Math.PI, 0);
			Bullets.Init(device);
			RealInput.Listen(Buttons.DPadUp, menuHandler);
			RealInput.Listen(Buttons.DPadDown, menuHandler);
			RealInput.Listen(Buttons.A, menuHandler);
			RealInput.Listen(Buttons.LeftShoulder, menuHandler);
			RealInput.Listen(Buttons.RightShoulder, menuHandler);
			RealInput.Listen(Buttons.Start, globalHandler);
			RealInput.Listen(Buttons.Back, globalHandler);
			base.Initialize();
		}

		protected override void UnloadContent() {
#if WIIMOTE
			if( mote != null ) {
				mote.Disconnect();
			}
#endif
			Bullets.Stop();
			SoundSystem.UnloadContent();
			base.UnloadContent();
		}

		private void globalHandler(Buttons button, Action action, PlayerIndex index, RealGameTime gameTime) {
			if( action == Action.Click ) {
				switch( button ) {
					case Buttons.Start:
						if( runGame ) {
							Paused = !Paused;
						}
						break;
					case Buttons.Back:
						if( runGame ) {
							StopGame();
						} else {
							Exit();
						}
						break;
				}
			}
		}

		private void menuHandler(Buttons button, Action action, PlayerIndex index, RealGameTime gameTime) {
			if( !runGame ) {
				if( action == Action.Click ) {
					switch( button ) {
						case Buttons.A:
							selectMenu();
							break;
						case Buttons.LeftShoulder:
							Game1.Level--;
							if( Game1.Level < 1 )
								Game1.Level = 1;
							break;
						case Buttons.RightShoulder:
							Game1.Level++;
							if( Game1.Level > 3 )
								Game1.Level = 3;
							break;
						case Buttons.DPadUp:
							moveUp();
							break;
						case Buttons.DPadDown:
							moveDown();
							break;						
					}
				}
			}
		}

		private void selectMenu() {
			foreach( Text text in curText ) {
				if( text.Focus ) {
					switch( text.Value ) {
						case "singleplayer":
							GameRunning = true;
							game = new Game1(Content, graphics);
							game.Initialize();
							runGame = true;
							Paused = false;							
							break;
						case "multiplayer":
							GameRunning = true;
							game = new RacerGame.RacerGame(Content, graphics);
                            ShaderSystem.SetParametersFor(ShaderSystem.ParametersPresets.NotSat);
							game.Initialize();
							runGame = true;
							Paused = false;							
							break;
						case "exit":
							Exit();
							break;
					}
					break;
				}
			}
		}

		private void moveUp() {
			for( int i = 1; i < curText.Count; i++ ) {
				if( curText[i].Focus ) {
					curText[i].Focus = false;
					curText[i - 1].Focus = true;
					break;
				}
			}
		}

		private void moveDown() {
			for( int i = 0; i < curText.Count - 1; i++ ) {
				if( curText[i].Focus ) {
					curText[i].Focus = false;
					curText[i + 1].Focus = true;
					break;
				}
			}
		}

		protected override void LoadContent() {            
			Content.RootDirectory = "Content";
			spriteFont = Content.Load<SpriteFont>(@"Fonts\FpsFont");
			noController = new TextGuide("Please connect an official Xbox 360 controller", spriteFont, TextAlign.Both, 1.3f, Color.Red, 0, null);
			noController.Alpha = 255;
			credits = new TextGuide("Made by Bo Bendtsen, Jonas Flensbak, Daniel Kromand, Jess Rahbek & Darryl Woodford, 2008", spriteFont, TextAlign.Horizontal | TextAlign.Bottom, 1f, new Color(0xa2,0x74,0x3c), 0, null);
			credits.Alpha = 255;
            ShaderSystem.Init(device, Content.Load<Effect>(@"Effects\NeonShader"));
			Bullets.Init(Content.Load<Effect>(@"Effects\PointSprite"), TextureTools.Gauss);
			logo = new Text("logo", Content.Load<Model>(@"Menu\ManInTheMiddle"), new Vector3(0, 30, 0), 0.0016f);
			singleplayer = new Text("singleplayer",Content.Load<Model>(@"Menu\Singleplayer"), new Vector3(0, 10, 0), 0.001f);
			MineEntity.InitModel(Content.Load<Model>(@"Models\Mine"));
			singleplayer.Focus = true;
			multiplayer = new Text("multiplayer",Content.Load<Model>(@"Menu\Multiplayer"), new Vector3(0, -10, 0), 0.001f);			
			curText.Add(singleplayer);
			curText.Add(multiplayer);
			curText.Add(new Text("exit", Content.Load<Model>(@"Menu\Exit"), new Vector3(0, -30, 0), 0.001f));
			foreach( Text text in curText ) {
				drawText.Add(text);
			}
			drawText.Add(logo);
            box = new BackgroundObject(Content.Load<Model>(@"Menu\Box"), new Vector3(0, 0, -120), 0.02f);

			SoundSystem.Init();
		}

		RealGameTime realGameTime = new RealGameTime();
		private void updateRealGameTime(GameTime gameTime) {
			realGameTime.ElapsedRealTime = gameTime.ElapsedRealTime;
			realGameTime.ElapsedGameTime = gameTime.ElapsedGameTime;
			realGameTime.TotalRealGameTime += gameTime.ElapsedGameTime;
		}

		
		private int mineAddInterval = 50;
		private int mineCount = 0;
		public static Random Rand = new Random();
		protected override void Update(GameTime gameTime) {
			for( int i = 0; i < 4; i++ ) {
				if( Vibration[i] > 1 ) { Vibration[i] = 1; }
				GamePad.SetVibration((PlayerIndex)i, Vibration[i], Vibration[i]);
				if( Vibration[i] > 0 ) { Vibration[i] -= 0.01f; }
				if( Vibration[i] < 0 ) { Vibration[i] = 0; }
			}

			controllerConnected = false;
			foreach( PlayerIndex index in RacerGame.RealInput.GamePadIndices ) {
				GamePadState state = GamePad.GetState(index);
				if( state.IsConnected ) {
					controllerConnected = true;
				}
			}

			if( Keyboard.GetState().IsKeyDown(Keys.Escape) ){
				if( runGame ) {
					game.UnloadContent();
					game = null;
					runGame = false;
				}
				Exit();
			}
			if( runGame ) {
				if( !Paused && controllerConnected ) {
					updateRealGameTime(gameTime);
					game.Update(realGameTime); // should just take totalgametimemillsecs, but too complicated to change now ...
				}
			} else {
				updateRealGameTime(gameTime);
				#if WIIMOTE
				if( mote != null ) {
					// wii control
					WiimoteState wstate = WiiState;					
					if( !wstate.ButtonState.Down && !wstate.ButtonState.Up ) {
						wiimove = false;
					}
					if( wstate.ButtonState.Down && !wiimove ) {
						moveDown();
						wiimove = true;
					}
					if( wstate.ButtonState.Up && !wiimove ) {
						moveUp();
						wiimove = true;
					}
					if( wstate.ButtonState.A ) {
						selectMenu();
					}
				}
				#endif
                // thumbstick control
				foreach( PlayerIndex index in RacerGame.RealInput.GamePadIndices ) {
					GamePadState state = GamePad.GetState(index);
					if( state.IsConnected ) {
						if( leftThumbNeutral ) {
							if( state.ThumbSticks.Left.Y < -0.4f ) {
								moveDown();
								leftThumbNeutral = false;
							} else if( state.ThumbSticks.Left.Y > 0.4f ) {
								moveUp();
								leftThumbNeutral = false;
							}
						} else if( Math.Abs(state.ThumbSticks.Left.Y) < 0.4 || Math.Abs(state.ThumbSticks.Left.Y) > 0.95 ) {
							leftThumbNeutral = true;
						}
					}
					break; // only first player
				}
				// mines
				if( mineCount == 0 ) {
					Mine mine = new Mine(new Vector3(Rand.Next(-80,80), 50, Rand.Next(-30,-10)));
					mine.Triggered = true;
					mines.Add(mine);
					mineAddInterval = Rand.Next(10, 50);
				}
				mineCount++;
				if( mineCount > mineAddInterval ) {
					mineCount = 0;
				}
				Bullets.Update(realGameTime);
			}
#if WIIMOTE
			if( mote != null ) {
				if( mote.WiimoteState.ButtonState.Home && runGame ) {
					game.UnloadContent();
					game = null;
					runGame = false;
				}
			}
#endif
			RealInput.Update(realGameTime);			
			base.Update(gameTime);
		}

		protected override void Draw(GameTime gameTime) {
			if( runGame && controllerConnected ) {
				game.Draw(realGameTime);				
            }
            else
            {				
                ShaderSystem.AnimateTexture();
                ShaderSystem.SetParametersFor(ShaderSystem.ParametersPresets.Menu);
                graphics.GraphicsDevice.Clear(Color.Black);

                ShaderSystem.CameraPositionParameter.SetValue(camera.Position);
                ShaderSystem.ViewParameter.SetValue(camera.View);
                ShaderSystem.ProjectionParameter.SetValue(camera.Projection);

                { // box
                    //box.Rotate(0.01f, 0.01f, 0.01f);
                    box.Update();                    
                    foreach (ModelMesh mesh in box.Model.Meshes)
                    {
                        ShaderSystem.ColorParameter.SetValue(Color.Black.ToVector4());
                        ShaderSystem.WorldParameter.SetValue(box.Transforms[mesh.ParentBone.Index] * box.Scale * box.RotationMatrix * box.PositionMatrix);
                        ShaderSystem.Draw(mesh);
                    }
                }

                List<Mine> newMines = new List<Mine>();
                foreach (Mine mine in mines)
                {
					mine.Update(realGameTime);
                    if (mine.RemoveFromTopMenu < 20)
                    {
                        newMines.Add(mine);
                    }
                    mine.Position += new Vector3(0, -0.6f, 0);
                    foreach (ModelMesh mesh in mine.Entity.Model.Meshes)
                    {
                        ShaderSystem.ColorParameter.SetValue(Color.Gold.ToVector4());
                        ShaderSystem.WorldParameter.SetValue(mine.Entity.Transforms[mesh.ParentBone.Index] * mine.Entity.Scale * mine.Entity.RotationMatrix * mine.Entity.PositionMatrix);
                        ShaderSystem.Draw(mesh);
                    }
                }
                mines = newMines;
				Bullets.Draw(camera);
				
				if( !controllerConnected ) {
					spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, SaveStateMode.SaveState);
					noController.Draw(spriteBatch);
					spriteBatch.End();
				} else {
					foreach( Text text in drawText ) {
						foreach( ModelMesh mesh in text.Model.Meshes ) {
							if( text.Focus ) {
								if( text.ScaleFactor < 1.3f ) {
									text.ScaleFactor += 0.02f;
								}
								ShaderSystem.ColorParameter.SetValue(Color.Gold.ToVector4());
							} else {
								if( text.ScaleFactor > 1 ) {
									text.ScaleFactor -= 0.02f;
								}
								ShaderSystem.ColorParameter.SetValue(Color.Gray.ToVector4());
							}
							ShaderSystem.WorldParameter.SetValue(text.Transforms[mesh.ParentBone.Index] * text.Scale * text.RotationMatrix * text.PositionMatrix);
							ShaderSystem.Draw(mesh);
						}
					}
					spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, SaveStateMode.SaveState);
					credits.Draw(spriteBatch);
					spriteBatch.End();
				}
            }			
			base.Draw(gameTime);
		}
	}
}
